#!/usr/bin/python
# -*- coding: UTF-8 -*-

## 计算用户之间的相似度
def user_similarity(train):
    '''1.建立:物品(item)->用户(user)倒排表'''
    item_users = dict()
    for userId in train.keys():
        for itemId in train.get(userId).keys():
            if itemId not in item_users:
                item_users[itemId] = set()
            item_users[itemId].add(userId)

    '''2.计算用户之间共同的物品数量'''
    intersection = dict()  # 交集:用户与用户之间相同的物品数据量 intersection[userId][userId]=物品数量
    commonMultiple = dict()  # 开平方根的分母(公倍数):每个用户拥有的物品数量 commonMultiple[userId]=物品数量
    for item, users in item_users.items():
        for i in users:
            if intersection.get(i, -1) == -1:
                intersection[i] = dict()
            if commonMultiple.get(i, -1) == -1:
                commonMultiple[i] = 0
            commonMultiple[i] += 1
            for j in users:
                if i == j:
                    continue
                elif intersection[i].get(j, -1) == -1:
                    intersection[i][j] = 0
                intersection[i][j] += 1
                # intersection[i][j] += 1 / math.log(1 + len(users))

    '''3.得到最终的相似度矩阵'''
    import math
    similarity = dict()
    for i, ru in intersection.items():
        if similarity.get(i, -1) == -1:
            similarity[i] = dict()
        for j, cuv in ru.items():
            if similarity[i].get(j, -1) == -1:
                similarity[i][j] = 0
            '''相似度 = len(集合1 & 集合2) / sqrt( len(集合1) * len(集合2) * 1.0)'''
            similarity[i][j] += cuv / math.sqrt(commonMultiple[i] * commonMultiple[j] * 1.0)

    return similarity


## 相似用户的物品
def user_recommend(userId, train, similarity, k):
    '''4.相似用户的物品'''
    rank = dict()
    for user, similarity in sorted(similarity[userId].items(), key=lambda x: x[1], reverse=True)[:k]:
        for item, rating in train[user].items():
            if item in train[userId].keys():
                continue
            elif rank.get(item, -1) == -1:
                rank[item] = 0
            rank[item] += similarity * float.fromhex(rating)
    return rank
